#include "stdafx.h"
#include "IDE.h"

SpreadBind::SpreadBind(double openSpread, double offsetSpread, double stopSpread)
	:m_openSpread(openSpread),m_offsetSpread(offsetSpread),m_stopSpread(stopSpread)
{
	if (DoubleComparer::less(m_stopSpread, m_openSpread))
	{
		//bearish:UP
		m_openComparer = DoubleComparer::less_equal;
		m_offsetComparer = DoubleComparer::greater_equal;
		m_safeComparer = DoubleComparer::greater;
	}
	else
	{
		//bullish:DOWN
		m_openComparer = DoubleComparer::greater_equal;
		m_offsetComparer = DoubleComparer::less_equal;		
		m_safeComparer = DoubleComparer::less;		
	}
}

SpreadBind::SpreadBind(double moveSpread)
	:m_moveSpread(moveSpread)
{

}


ArbitrageLegs::ArbitrageLegs(MarketSnapshot const& marketSnapshot, SpreadContracts const& contracts, Direction::TYPE fartherDirection, SpreadBind const& bind, HedgeFlag::TYPE hedgeflag) 
	:m_fartherOpenLeg(marketSnapshot.GetMarket(contracts.GetFarther()),fartherDirection,Operation::OPEN,hedgeflag)
	,m_closerOpenLeg(marketSnapshot.GetMarket(contracts.GetCloser()),m_fartherOpenLeg.GetNegateDirection(),Operation::OPEN,hedgeflag)
	,m_fartherOffsetLeg(marketSnapshot.GetMarket(contracts.GetFarther()),m_fartherOpenLeg.GetNegateDirection(),m_fartherOpenLeg.GetNegateOperation(),hedgeflag)
	,m_closerOffsetLeg(marketSnapshot.GetMarket(contracts.GetCloser()),m_fartherOpenLeg.GetDirection(),m_fartherOpenLeg.GetNegateOperation(),hedgeflag)
	,m_bind(bind)
	,m_minorOpenLeg(contracts.IsMajorEqualFarther() ? m_closerOpenLeg : m_fartherOpenLeg)
	,m_majorOpenLeg(contracts.IsMajorEqualFarther() ? m_fartherOpenLeg : m_closerOpenLeg)
	,m_minorOffsetLeg(contracts.IsMajorEqualFarther() ? m_closerOffsetLeg : m_fartherOffsetLeg)
	,m_majorOffsetLeg(contracts.IsMajorEqualFarther() ? m_fartherOffsetLeg : m_closerOffsetLeg)
{
}

ArbitrageLegs::ArbitrageLegs(ArbitrageLegs const& other) 
	:m_fartherOpenLeg(other.GetFartherOpenLeg())
	,m_closerOpenLeg(other.GetCloserOpenLeg())
	,m_fartherOffsetLeg(other.GetFartherOffsetLeg())
	,m_closerOffsetLeg(other.GetCloserOffsetLeg())
	,m_bind(other.GetBind())
	,m_minorOpenLeg(other.IsMajorEqualFarther() ? m_closerOpenLeg : m_fartherOpenLeg)
	,m_majorOpenLeg(other.IsMajorEqualFarther() ? m_fartherOpenLeg : m_closerOpenLeg)
	,m_minorOffsetLeg(other.IsMajorEqualFarther() ? m_closerOffsetLeg : m_fartherOffsetLeg)
	,m_majorOffsetLeg(other.IsMajorEqualFarther() ? m_fartherOffsetLeg : m_closerOffsetLeg)
{
}

ArbitrageLegs ArbitrageLegs::CreateBearish(MarketSnapshot const& marketSnapshot, SpreadContracts const& contracts, HedgeFlag::TYPE hedgeFlag)
{
	return ArbitrageLegs(marketSnapshot, contracts, Direction::BUY, SpreadBind::CreateBearish(), hedgeFlag);
}

ArbitrageLegs ArbitrageLegs::CreateBullish(MarketSnapshot const& marketSnapshot, SpreadContracts const& contracts, HedgeFlag::TYPE hedgeFlag)
{
	return ArbitrageLegs(marketSnapshot, contracts, Direction::SELL, SpreadBind::CreateBullish(), hedgeFlag);
}

ArbitrageLegs ArbitrageLegs::Create(MarketSnapshot const& marketSnapshot, SpreadContracts const& contracts, SpreadBind const& band, HedgeFlag::TYPE hedgeFlag)
{
	return band.IsSameType(SpreadBind::CreateBearish()) ? CreateBearish(marketSnapshot,contracts,hedgeFlag) : CreateBullish(marketSnapshot,contracts,hedgeFlag);
}

bool ArbitrageLegs::UpdateBind(SpreadBind const& bind)
{
	if (bind.IsSameType(m_bind))
	{
		m_bind = bind;
		return true;
	}
	return false;
}

double ArbitrageLegs::GetOpponentOpenSpread(Dealing const& openedDealing) const
{
	if (GetFartherOpenLeg().Match(openedDealing.GetContractIndex(),openedDealing.GetDirection(),openedDealing.GetOperation()))
	{
		return openedDealing.GetOrderPrice() - GetCloserOpenLeg().GetOpponentPrice();
	}
	else if (GetCloserOpenLeg().Match(openedDealing.GetContractIndex(),openedDealing.GetDirection(),openedDealing.GetOperation()))
	{
		return GetFartherOpenLeg().GetOpponentPrice() - openedDealing.GetOrderPrice();
	}
	throw CONTRACT_INDEX_NOTFUND;
}

double ArbitrageLegs::GetOpponentOffsetSpread(Dealing const& openedDealing) const
{
	if (GetFartherOpenLeg().Match(openedDealing.GetContractIndex(),openedDealing.GetDirection(),openedDealing.GetOperation()))
	{
		return openedDealing.GetOrderPrice() - GetCloserOffsetLeg().GetOpponentPrice();
	}
	else if (GetCloserOpenLeg().Match(openedDealing.GetContractIndex(),openedDealing.GetDirection(),openedDealing.GetOperation()))
	{
		return GetFartherOffsetLeg().GetOpponentPrice() - openedDealing.GetOrderPrice();
	}
	throw CONTRACT_INDEX_NOTFUND;
}

double ArbitrageLegs::GetProfit(double spread, int quantity) const
{
	int sign = m_bind.IsSameType(SpreadBind::CreateBearish()) ? 1 : -1;
	double basicProfit = GetOpponentOffsetSpread() - spread;
	if (DoubleComparer::equal(0.00, basicProfit))
	{
		return 0.00;
	}
	return sign * basicProfit * quantity * m_majorOpenLeg.GetMarket().GetVariety().GetMultiplier();
}

